/*
 * Copyright (c) 2017-present, CV4J Contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cv4j.core.filters;

import com.cv4j.core.datamodel.ByteProcessor;
import com.cv4j.image.util.Tools;

/**
 * 渐变滤光片
 *
 * @author dev
 * @date 2021/07/22
 */
public class GradientFilter {
    /**
     * 索贝尔x
     */
    public static final int[][] SOBEL_X = new int[][]{{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
    /**
     * sobel y
     */
    public static final int[][] SOBEL_Y = new int[][]{{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}};

    /**
     * direction parameter
     */
    public static final int X_DIRECTION = 0;
    /**
     * y方向
     */
    public static final int Y_DIRECTION = 2;
    /**
     * xy方向
     */
    public static final int XY_DIRECTION = 4;
    /**
     * 方向
     */
    private int direction;
    /**
     * 是索贝尔
     */
    private boolean isSobel;

    /**
     * 渐变滤光片
     */
    public GradientFilter() {
        direction = XY_DIRECTION;
        isSobel = true;
    }

    /**
     * 设置soble
     *
     * @param sobel 索贝尔
     */
    public void setSoble(boolean sobel) {
        this.isSobel = sobel;
    }

    /**
     * 得到方向
     *
     * @return int
     */
    public int getDirection() {
        return direction;
    }

    /**
     * 设置方向
     *
     * @param direction 方向
     */
    public void setDirection(int direction) {
        this.direction = direction;
    }

    /**
     * 梯度
     *
     * @param src src
     * @return {@link int[]}
     */
    public int[] gradient(ByteProcessor src) {
        int width = src.getWidth();
        int height = src.getHeight();
        int[] outPixels = new int[width * height];
        int index = 0;
        int index2 = 0;
        double xred = 0;
        double yred = 0;
        int newRow;
        int newCol;
        float min = 255;
        float max = 0;
        byte[] intput = src.getGray();
        for (int row = 0; row < height; row++) {
            int pv = 0;
            for (int col = 0; col < width; col++) {
                index = row * width + col;
                for (int subrow = -1; subrow <= 1; subrow++) {
                    for (int subcol = -1; subcol <= 1; subcol++) {
                        newRow = row + subrow;
                        newCol = col + subcol;
                        if (newRow < 0 || newRow >= height) {
                            newRow = row;
                        }
                        if (newCol < 0 || newCol >= width) {
                            newCol = col;
                        }
                        index2 = newRow * width + newCol;
                        pv = intput[index2] & 0xff;
                        xred += (SOBEL_X[subrow + 1][subcol + 1] * pv);
                        yred += (SOBEL_Y[subrow + 1][subcol + 1] * pv);
                    }
                }

                double mred = Math.sqrt(xred * xred + yred * yred);
                max = Math.max(Tools.clamp((int) mred), max);
                min = Math.min(Tools.clamp((int) mred), min);
                if (direction == XY_DIRECTION) {
                    outPixels[index] = Tools.clamp((int) mred);
                } else if (direction == X_DIRECTION) {
                    outPixels[index] = Tools.clamp((int) yred);
                } else if (direction == Y_DIRECTION) {
                    outPixels[index] = Tools.clamp((int) xred);
                } else {
                    // as default, always XY gradient
                    outPixels[index] = Tools.clamp((int) mred);
                }
                // cleanup for next loop
                newRow = newCol = 0;
                xred = 0;
                yred = 0;
            }
        }
        return outPixels;
    }
}
